package com.yun.newBlog.blog.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yun.newBlog.blog.Handler.MyAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.ForwardLogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.web.ProviderSignInUtils;
import org.springframework.social.security.SpringSocialConfigurer;
import org.springframework.web.cors.CorsUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.PrintWriter;

@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用方法安全设置
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//    @Bean
//    public PasswordEncoder passwordEncoder(){
//        return new BCryptPasswordEncoder();
//    }
//
//    @Autowired
//    private PasswordEncoder passwordEncoder;

    //@Qualifier("myUserDetailsService")
    //@Autowired
    //public UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private SpringSocialConfigurer yunSocialSecurityConfig;

    @Autowired
    @Qualifier("myUserDetailsService")
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception{

        /**
         * 1. 表单登陆
         * 2. /blog/**路径下的请求不用认证
         * 3. 其他请求需要认证
         */
        http.

            apply(yunSocialSecurityConfig).
            and().

            /**
             * 表单登录
             * 1. 设置进行登录的url
             * 2. 登录成功后跳转的地址
             */
            formLogin().
                loginProcessingUrl("/login").
                successHandler(new ForwardAuthenticationSuccessHandler("/login/succeed")).
                failureHandler(new ForwardAuthenticationFailureHandler("/login/failed")).
            and().

            /**
             * 记住我
             */
            rememberMe()
                .key("yubuyun") // 私钥
                .tokenValiditySeconds(2149200) // token有限时间，单位秒
                .tokenRepository(tokenRepository())
            .and().

            /*
                设置登出成功后的地址
             */
            logout().
                logoutSuccessHandler(new ForwardLogoutSuccessHandler("/logout/succeed")).
            and().

            authorizeRequests()
                .antMatchers("/blog/**").permitAll()    // 博客访问地址
                .antMatchers("/login/**").permitAll()   // 表单登录请求
                .antMatchers("/logout/**").permitAll()  // 退出登陆请求
                .antMatchers("/auth/**").permitAll()    // qq登录跳转地址
                .antMatchers("/signup/**").permitAll()  // 社交登录成功后会访问注册请求
                .antMatchers("/main/**").permitAll()    // 首页地址
                .anyRequest().authenticated()
                .and()

            // 禁用跨站请求伪造，不然前台访问会有跨域问题
            .csrf().disable();
    }

    @Bean
    public JdbcTokenRepositoryImpl tokenRepository(){
        JdbcTokenRepositoryImpl jdbcImpl = new JdbcTokenRepositoryImpl();
        jdbcImpl.setDataSource(dataSource);
        return jdbcImpl;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder()); // 设置密码加密方式
        return authenticationProvider;
    }

    /**
     * 应用启动过程中会调用该方法
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // ensure the passwords are encoded properly

        /*
         * demo:如何创建一个用户,用户名为yubuyun,密码为abc123
         */
//        String password =passwordEncoder.encode("abc123");
//        User user = new User("yubuyun", password, true, true, true, false, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
//        auth.jdbcAuthentication().dataSource(dataSource).withUser(user);

        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(authenticationProvider());

    }

    @Bean
    public SpringSocialConfigurer yunSocialSecurityConfig(){
        String filterProcessUrl = "/auth";
        YunSpringSocialConfigurer yunSpringSocialConfigurer = new YunSpringSocialConfigurer(filterProcessUrl);
        yunSpringSocialConfigurer.signupUrl("/signup");
        return yunSpringSocialConfigurer;
    }

}
